import os
import pyRXP
from wxPython.wx import wxColour,wxPoint,wxRect,wxPen
from wxPython.ogl import wxShape

settings = {}
listOfParsedPortFiles = {}
listOfParsedUnitOpFiles = {}

def initialize():
    fil = 'Settings/settings.xml'
    f = open(fil).read()
    parser = pyRXP.Parser()
    tup = parser.parse(f)
    tree = TreeGenerator(tup)
    for child,list in tree.child.items():
        r = int(list[0].attributes['r'])
        g = int(list[0].attributes['g'])
        b = int(list[0].attributes['b'])
        settings[ child ] = wxColour( r , g , b  )

def buildPorts():
    path = 'Ports\\'
    lis =  os.listdir(path)
    for fil in lis:
        parsedFil = PortFileParser(path + fil)
        listOfParsedPortFiles[parsedFil.type] = parsedFil
    
def buildUnitOps():
    path = 'UnitOp\\'
    lis =  os.listdir(path)
    for fil in lis:
        parsedFil = UnitOpFileParser(path + fil)
        listOfParsedUnitOpFiles[parsedFil._class] = parsedFil

class TreeGenerator:
    def __init__(self,tup):
        self.tag =  tup[0]
        self.attributes = tup[1]
        self.child = {}
        self.end = tup[3]
        if (tup[2] == None):
            pass
        elif (len(tup[2]) == 1):
            pass
        else:
            for i in range(len(tup[2])/2):
                pos = (i * 2) + 1
                key = tup[2][pos][0]
                if self.child.has_key(key):
                    self.child[ key ].append( TreeGenerator(tup[2][pos]) )
                else:
                    self.child[ key ] = []
                    self.child[ key ].append( TreeGenerator(tup[2][pos]) )
                #there can be multiple instances of the same tag at the same level...
                #hence the use of lists for each key in the dictionary
                
class PortFileParser:
    def __init__(self,fil):
        fc = open(fil).read()
        p = pyRXP.Parser()
        tup = p.parse(fc)  #temporary buffer to hold the contents of the parsed XML file
        tree = TreeGenerator(tup)
        self.type = tree.attributes['type']
        self.flow = tree.attributes['flow']

        self.struct = {}
        """************************************************************************************************************
            care should be taken to delete those keys from the dictionary position_within before reaching the last loop.
            For example the colours key has been deleted in the if structure after processing.
            Fixing the unit op draw problem 
        """

        if tree.child.has_key('colours'):
            colour_tree = tree.child['colours'][0]
            
            brush_tree = colour_tree.child['brush'][0]
            red = int(brush_tree.attributes['r'])
            green = int(brush_tree.attributes['g'])
            blue = int(brush_tree.attributes['b'])
            self.brush = wxColour(red,green,blue)
            
            pen_tree = colour_tree.child['pen'][0]
            red = int(pen_tree.attributes['r'])
            green = int(pen_tree.attributes['g'])
            blue = int(pen_tree.attributes['b'])
            self.pen = wxColour(red,green,blue)
            
            connector_tree = colour_tree.child['connectors'][0]
            red = int(connector_tree.attributes['r'])
            green = int(connector_tree.attributes['g'])
            blue = int(connector_tree.attributes['b'])
            self.conn_colour = wxColour(red,green,blue)

            del tree.child['colours']
        else:
            self.brush = wxColour(0,0,0)
            self.pen = wxColour(255,255,255)
            
        for orient,list in tree.child.items():
            self.struct[orient] = DiagramStructure(list[0])
       
        """*********************************************************************************************************"""

class UnitOpFileParser:
    def __init__(self,fil):
        fc = open(fil).read()
        p = pyRXP.Parser()
        tup = p.parse(fc)  #temporary buffer to hold the contents of the parsed XML file
        tree = TreeGenerator(tup)
        self.name = tree.attributes['name']
        self._class = tree.attributes['_class']
        self.args = tree.attributes['args']
        if tree.attributes.has_key('rotate'):
            if tree.attributes['rotate'] == 'true':
                self.rotate = True
            else:
                self.rotate = False
        else:
            self.rotate = True
        if tree.attributes.has_key('scale'): self.scale = int(tree.attributes['scale'])
        else: self.scale = 2.0

        if tree.attributes.has_key('red'):
            red = int(tree.attributes['red'])
            blue = int(tree.attributes['blue'])
            green = int(tree.attributes['green'])
            self.pen_colour = wxColour(red,green,blue)
        else:
            self.pen_colour = wxColour(0,0,0)
            
        self.listOfPorts = {}
        dict = {}
        for type,sub_tree_list in tree.child['ports'][0].child.items():
            sub_tree = sub_tree_list[0]
            list = []
            type_details = sub_tree.attributes
            #each variety of port may have multiple instances in the UOP if editable is false(fixed ports)
            if type_details['editable'] == 'false':#in that case, append the list of dictionaries containing individual port details
                if sub_tree.child.has_key('coords'):
                    for ports in sub_tree.child['coords']: 
                        list.append( ports.attributes )
                dict[ type ] = { 'type_details':type_details , 'param':list } 
            else:#if editable is true-->ports can be added....assumption that they can be added only on one side
                #of the unitop and in only one orientation. Hence skip the list containing individual port details
                dict[ type ] = { 'type_details':type_details }                    
        del tree.child['ports']
        for type,for_eachType in dict.items():#for each variety of port
            ports_parameters = []
            if for_eachType.has_key('param'):#if editable is false then it may have instances of fixed ports each having different locations and orientations
                for port_details in for_eachType['param']:
                    dict = {}
                    x = (int(port_details['posx'])) 
                    y = (int(port_details['posy'])) 
                    port_origin = self.CalculateOrigin( x , y , port_details['location'] )
                    dict = { 'type':type , 'orient':port_details['orientation'] , 'origin':port_origin , 'location':port_details['location'] }
                    ports_parameters.append(dict)
                for_eachPortType = { 'type_details':for_eachType['type_details'] , 'param':ports_parameters } #for each type of port details and list of ports    
            else:#else if editable is true then all the ports are assumed to have same location and orientation hence the list of their details is skipped
                for_eachPortType = { 'type_details':for_eachType['type_details'] } #for each type of port details and list of ports    
            self.listOfPorts[type] = for_eachPortType

        self.uopStruct = DiagramStructure(tree)
        
    def CalculateOrigin(self,x,y,loc):
        """the different locations possible are:
        
            top        above the figure but within the left max and right max
            top-left   above the figure but beyond the left max..so on
            top-right
            right
            bottom-right
            bottom
            bottom-left
            left
            inside     within the figure
            
            These locations indicate where the centre of the port exists.
        """
        location = { 'inside':(1,1),
                     'top-left':(-1,-1),
                     'top':(1,-1),
                     'top-right':(1,-1),
                     'right':(1,1),
                     'bottom-right':(1,1),
                     'bottom':(1,1),
                     'bottom-left':(-1,1),
                     'left':(-1,1) }

        pair = location[loc]
        return( ( ((x * pair[0]))/100.0  , ((y * pair[1]))/100.0 ) )

class DiagramStructure:
    def __init__(self,tree):
        #read the size for the diagram.
        self.orientation = tree.tag
        x = int(tree.attributes['sizx'])
        y = int(tree.attributes['sizy'])
        self.size = wxPoint( x,y )
        self.locus = {} #buffer to hold line co-ords or details of other geometric figures
        
        #loop to read in co-ords for straight lines in terms of percentage deviation from the default co-ords read earlier
        #subtract 50% from each co-ord to send the figure to the centre from fourth quadrant
        if tree.child.has_key('arc'):
            arc_tree = tree.child['arc'][0]
            if arc_tree.child.has_key('coords'):
                arcList = [ ] 
                for coords in arc_tree.child['coords']:
                    x = int(coords.attributes['x']) - 50
                    y = int(coords.attributes['y']) - 50
                    w = int(coords.attributes['w'])
                    h = int(coords.attributes['h'])
                    s = int(coords.attributes['s'])
                    e = int(coords.attributes['e'])
                    topleftx = int((x / 100.0) * self.size.x )
                    toplefty = int((y / 100.0) * self.size.y)
                    width = int((w / 100.0) * self.size.x )
                    height = int((h / 100.0) * self.size.y )
                    rect = wxRect(topleftx, toplefty, width, height)
                    arcList.append( { 'rect':rect ,'start':s , 'end':e } )
                self.locus['arc'] = arcList

        if tree.child.has_key('straight'):
            straight_tree = tree.child['straight'][0]
            if straight_tree.child.has_key('coords'):
                straightLine = [ ] 
                for coords in straight_tree.child['coords']:
                    x1 = int(coords.attributes['x1']) - 50
                    y1 = int(coords.attributes['y1']) - 50
                    x2 = int(coords.attributes['x2']) - 50
                    y2 = int(coords.attributes['y2']) - 50
                    point1 = wxPoint(int((x1 / 100.0) * self.size.x) , int((y1 / 100.0)* self.size.y) )
                    point2 = wxPoint(int((x2 / 100.0) * self.size.x) , int((y2 / 100.0)* self.size.y) )
                    dict = { 'point1':point1 , 'point2':point2 }
                    straightLine.append( dict )
                self.locus['straight'] = straightLine
